﻿
#include"ProcessTools.hpp"


#ifdef WIN32

#include< Windows.h>
#include<filesystem>
#include <psapi.h>
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Psapi.lib")

namespace MMF 
{

    ProcessHdl ProcessTools::RunExecutable(const std::string& path, bool showWindow)
    {
		std::string exePath = path;
		std::filesystem::path checkPath = exePath;
		if (checkPath.extension().string() != ".exe")
			exePath = exePath + ".exe";
		
        char desktop[] = "WinSta0\\Default";
        STARTUPINFOA si = {};
        si.cb = sizeof(STARTUPINFOA);
		si.lpDesktop = desktop;
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.wShowWindow = showWindow ? SW_SHOW : SW_HIDE;	//是否显示窗口

        PROCESS_INFORMATION pi = {};
		SECURITY_ATTRIBUTES saProcess = {}, saThread = {};
		saProcess.nLength = sizeof(saProcess);
		saProcess.lpSecurityDescriptor = NULL;
		saProcess.bInheritHandle = true;
		saThread.nLength = sizeof(saThread);
		saThread.lpSecurityDescriptor = NULL;
		saThread.bInheritHandle = true;

        char cmd[4096] = {}; //命令行参数
		memcpy(cmd, exePath.data(), exePath.size());

        auto ret = ::CreateProcessA(nullptr, cmd, &saProcess, &saThread, false,
				CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
        
		return ret == 0 ? 0 : pi.dwProcessId;	//0虽然是有效进程，但是系统的idle进程的pid为0，所以这里认为0是无效的
    }

	ProcessHdl ProcessTools::ExcuteCommand(const std::string& paramCmd, bool showWindow)
	{
        char desktop[] = "WinSta0\\Default";
        STARTUPINFOA si = {};
        si.cb = sizeof(STARTUPINFOA);
		si.lpDesktop = desktop;
		si.dwFlags = STARTF_USESHOWWINDOW;
		si.wShowWindow = showWindow ? SW_SHOW : SW_HIDE;	//是否显示窗口

        PROCESS_INFORMATION pi = {};
		SECURITY_ATTRIBUTES saProcess = {}, saThread = {};
		saProcess.nLength = sizeof(saProcess);
		saProcess.lpSecurityDescriptor = NULL;
		saProcess.bInheritHandle = true;
		saThread.nLength = sizeof(saThread);
		saThread.lpSecurityDescriptor = NULL;
		saThread.bInheritHandle = true;

        char cmd[4096] = {}; //命令行参数
		memcpy(cmd, paramCmd.data(), paramCmd.size());

        auto ret = ::CreateProcessA(nullptr, cmd, &saProcess, &saThread, false,
				CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
        
		return ret == 0 ? 0 : pi.dwProcessId;	//0虽然是有效进程，但是系统的idle进程的pid为0，所以这里认为0是无效的
	}

	bool ProcessTools::KillProcess(ProcessHdl pid)
	{
		::HANDLE phd = ::OpenProcess(PROCESS_TERMINATE, FALSE, pid);
		bool ret = ::TerminateProcess(phd, -9);		//错误码按linux的来
		CloseHandle(phd);
		return ret;
	}

	bool ProcessTools::CheckProcessRun(ProcessHdl pid)
	{
		//获取所有的进程
		DWORD* pids = new DWORD[1024 * 256];
		DWORD num = 0;
		if (!EnumProcesses(pids, sizeof(DWORD) * 1024 * 256, &num))
        	return true;
		num /= sizeof(DWORD);
	
		//对进程进行遍历判断是否存在
		for (DWORD i = 0; i < num; i++)
		{
			if (pids[i] != 0 && pids[i] == pid)
				return true;
		}

		return false;
	}

}


#else 


#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<errno.h>
#include<cstring>
#include<filesystem>


namespace MMF 
{

	ProcessHdl ProcessTools::RunExecutable(const std::string& path, bool showWindow)
    {
		pid_t pid = vfork();
		if (pid == 0)
		{
			if (!showWindow)
			{
				execl(path.data(), path.data(), NULL);			//不在终端中显示
			}
			else 
			{
				char cmd[1024] = {};
                sprintf(cmd, "gnome-terminal -- \"%s\"", path.data()); //在新终端中打开
				system("cmd");
			}
		}

		return (ProcessHdl)pid;					//0虽然是有效进程，但是系统的idle进程的pid为0，所以这里认为0是无效的
	}

	ProcessHdl ProcessTools::ExcuteCommand(const std::string& paramCmd, bool showWindow)
	{
		pid_t pid = vfork();
		if (pid == 0)
		{
			if (!showWindow)
			{
				execl(paramCmd.data(), paramCmd.data(), NULL);			//不在终端中显示
			}
			else 
			{
				char cmd[1024] = {};
				sprintf(cmd, "gnome-terminal -- \"%s\"", paramCmd.data()); //在新终端中打开
				system("cmd");
			}
		}

		return (ProcessHdl)pid;					//0虽然是有效进程，但是系统的idle进程的pid为0，所以这里认为0是无效的
	}

	bool ProcessTools::KillProcess(ProcessHdl pid)
	{
		int ret = kill(pid, -9);
		return ret == 0 ? true : false;
	}

	bool ProcessTools::CheckProcessRun(ProcessHdl pid)
	{
		char filePath[128] = {};
		sprintf(filePath, "/proc/%d", pid);		//linux下运行的进程会在/proc有自己的pid命名的目录
		return std::filesystem::exists(filePath);
	}
}

#endif
